package com.panopset.gui.container;

import java.awt.FlowLayout;
import java.awt.LayoutManager;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import com.panopset.centralen.UniqueKey;
import com.panopset.gui.LookAndFeel;
import com.panopset.gui.TPanel;
import com.panopset.swing.Field;
import com.panopset.swing.FieldDefaultHardCoded;
import com.panopset.swing.FieldValue;
import com.panopset.swing.FontManager;
import com.panopset.swing.Scaffolding;

/**
 * Pan field.
 * 
 * Fields should do the following:
 * <ul>
 * <li>
 * Have static access to font, color, other attributes that will be common to an
 * application.</li>
 * <li>
 * Persist with a document, or application.</li>
 * <li>
 * Allow for validation. (text, number, file, directory).</li>
 * </ul>
 * 
 * @author Karl Dinwiddie
 * 
 * @param <T>
 *            T extends JComponent.
 */
public abstract class PanField<T extends JComponent> extends PanNoBorderField<T> {

	/**
	 * Layout.
	 */
	private LayoutManager playout;
	
	/**
	 * @param borderTitle
	 *            Border title.
	 * @param toolTipText
	 *            Tool tip text.
	 * @param defaultValue
	 *            Default value.
	 * @param layout
	 *            Layout.
	 */
	public PanField(final String borderTitle, final String toolTipText,
			final String defaultValue, final LayoutManager layout) {
		this(borderTitle, toolTipText, defaultValue);
		playout = layout;
	}

	/**
	 * @param toolTipText
	 *            Tool tip text.
	 * @param defaultValue
	 *            Default value.
	 * @param layout
	 *            Layout.
	 */
	public PanField(final String toolTipText, final String defaultValue,
			final LayoutManager layout) {
		this(null, toolTipText, defaultValue);
		playout = layout;
	}

	/**
	 * @param borderTitle
	 *            Border title.
	 * @param toolTipText
	 *            Tool tip text.
	 * @param defaultValue
	 *            Default value.
	 */
	public PanField(final String borderTitle, final String toolTipText,
			final String defaultValue) {
		super(defaultValue, toolTipText);
		setFieldDefault(new FieldDefaultHardCoded(defaultValue));
		pborderTitle = borderTitle;
	}


	/**
	 * @return Layout.
	 */
	protected abstract LayoutManager createLayout();


	/**
	 * Border title.
	 */
	private String pborderTitle;

	/**
	 * @return Border title.
	 */
	public final String getBorderTitle() {
		if (pborderTitle == null) {
			pborderTitle = "";
		}
		return pborderTitle;
	}

	/**
	 * Normal border.
	 */
	private TitledBorder normalBorder;
	/**
	 * Wait border.
	 */
	private TitledBorder waitBorder;
	/**
	 * Alert border.
	 */
	private TitledBorder alertBorder;
	/**
	 * In progress border.
	 */
	private TitledBorder inprogressBorder;

	/**
	 * Set border title.
	 * 
	 * @param newBorderTitle
	 *            New border title.
	 */
	public final void setBorderTitle(final String newBorderTitle) {
		pborderTitle = newBorderTitle;
		getNormalBorder().setTitle(pborderTitle);
		getWaitBorder().setTitle(pborderTitle);
		getAlertBorder().setTitle(pborderTitle);
		getInprogressBorder().setTitle(pborderTitle);
	}


	/**
	 * @return Normal titled border.
	 */
	protected final TitledBorder getNormalBorder() {
		if (isWaitingForInput()) {
			return getAlertBorder();
		}
		if (normalBorder == null) {
			LineBorder lb = new LineBorder(
					LookAndFeel.Colors.BORDER_COLOR_NORMAL.getColor(), 1);
			normalBorder = new TitledBorder(lb, pborderTitle);
			FontManager
					.register(normalBorder, FontManager.FontType.borderTitle);
			normalBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_NORMAL
					.getColor());
		}
		return normalBorder;
	}

	/**
	 * @return Wait titled border.
	 */
	protected final TitledBorder getWaitBorder() {
		if (waitBorder == null) {
			LineBorder lb = new LineBorder(LookAndFeel.Colors.BORDER_COLOR_WAIT
					.getColor(), 1);
			waitBorder = new TitledBorder(lb, pborderTitle);
			waitBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_WAIT
					.getColor());
			FontManager.register(waitBorder, FontManager.FontType.borderTitle);
		}
		return waitBorder;
	}

	/**
	 * @return Alert titled border.
	 */
	protected final TitledBorder getAlertBorder() {
		if (alertBorder == null) {
			LineBorder lb = new LineBorder(
					LookAndFeel.Colors.BORDER_COLOR_ALERT.getColor(), 1);
			alertBorder = new TitledBorder(lb, pborderTitle);
			alertBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_ALERT
					.getColor());
			FontManager.register(alertBorder, FontManager.FontType.borderTitle);
			setNormalHighlighting();
		}
		return alertBorder;
	}

	/**
	 * @return In progress titled border.
	 */
	protected final TitledBorder getInprogressBorder() {
		if (inprogressBorder == null) {
			LineBorder lb = new LineBorder(
					LookAndFeel.Colors.BORDER_COLOR_INPROGRESS.getColor(), 1);
			inprogressBorder = new TitledBorder(lb, pborderTitle);
			inprogressBorder
					.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_INPROGRESS
							.getColor());
			FontManager.register(inprogressBorder,
					FontManager.FontType.borderTitle);
			setNormalHighlighting();
		}
		return inprogressBorder;
	}

	/**
	 * Set normal highlighting for the boder title.
	 */
	public final void setNormalHighlighting() {
		if (pborderTitle == null) {
			return;
		}
		getPanel().setBorder(getNormalBorder());
		reset();
	}

	/**
	 * If you want to show something in progress, use this.
	 */
	public final void setWaitHighlighting() {
		if (pborderTitle == null) {
			return;
		}
		getPanel().setBorder(getWaitBorder());
		reset();
	}

	/**
	 * Set alert highlighting.
	 */
	public final void setAlertHighlighting() {
		if (pborderTitle == null) {
			return;
		}
		getPanel().setBorder(getAlertBorder());
		reset();
	}

	/**
	 * Set in progress highlighting.
	 */
	public final void setInprogressHighlighting() {
		if (pborderTitle == null) {
			return;
		}
		getPanel().setBorder(getInprogressBorder());
		reset();
	}

	/**
	 * Reset.
	 */
	public final void reset() {
		getPanel().invalidate();
	}


	/**
	 * Check to see if we need to alert the user for input action.
	 */
	protected void checkInput() {
	}

	/**
	 * Is waiting for input.
	 */
	private boolean isWaitingForInput = false;

	/**
	 * @return True if waiting for input.
	 */
	private boolean isWaitingForInput() {
		checkInput();
		return isWaitingForInput;
	}

	/**
	 * @param value
	 *            Value to set.
	 */
	public final void setWaitingForInput(final boolean value) {
		isWaitingForInput = value;
	}
	

	/**
	 * @return Layout.
	 */
	final LayoutManager getLayout() {
		if (playout == null) {
			playout = createLayout();
		}
		return playout;
	}
    
	/**
	 * Containing panel.
	 */
	private TPanel panel;

	/**
	 * @return Containing panel.
	 */
	public final JPanel getPanel() {
		if (panel == null) {
			panel = new TPanel.Builder().layout(getLayout()).construct();
			panel.setBackground(LookAndFeel.Colors.BG_COLOR.getColor());
			panel.setToolTipText(ptoolTipText);
			panel.add(getInnerComponent());
			setNormalHighlighting();
		}
		return panel;
	}
}
